package com.dashan.backend;
import static com.dashan.Constants.PUBLIC_GROUP_NAME;

import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.jdo.JDOHelper;
import javax.jdo.Transaction;

import com.dashan.backend.datastore.DsFriend;
import com.dashan.backend.datastore.DsFriendGroup;
import com.dashan.backend.datastore.DsUser;

public class AccessControlManager {

    public enum Permission {
        PROFILE("Profile", 0x1 << 0), 
        CURRENT_POSITION("Current Position", 0x1 << 1), 
        HISTORY_POSITION("History Position", 0x1 << 2);

        private static final Map<String, Permission> lookup = new HashMap<String, Permission>();

        static {
            for(Permission p : EnumSet.allOf(Permission.class)) {
                lookup.put(p.getName(), p);
            }
        }
        
        private String name;
        private long permissionBits;

        private Permission(String name, long permissionBits) {
            this.name = name;
            this.permissionBits = permissionBits;
        }

        public String getName() {
            return name;
        }

        public long getPermission() {
            return permissionBits;
        }
        public static Permission get(String name) {
            return lookup.get(name);
        }
    }
    
    public static Long PermissionSet2Bits(Set<Permission> permissions) {
        Long permissionBits = 0x0L;
        for (Permission p : permissions) {
            permissionBits |= p.getPermission();
        }
        return permissionBits;
    }
    
    public static Set<Permission> PermissionBits2Set(long permissionBits) {
        HashSet<Permission> permissions = new HashSet<Permission>();
        for(Permission p : EnumSet.allOf(Permission.class)) {
            if ((p.getPermission() & permissionBits) != 0L) {
                permissions.add(p);
            }
        }
        return permissions;
    }
    
    /** Returns if UserA has permission p to access userB. **/
    public static boolean hasPermission(DsUser userA, DsUser userB, Permission p) {
        DsFriend friendA = userB.getFriend(userA.getUserName());
        if (friendA == null) {
            return ((userB.getGroup(PUBLIC_GROUP_NAME).getPermissionBits() & 
                     p.getPermission()) != 0x0L);
        } else {
            return ((friendA.getPermission() & p.getPermission()) != 0x0L);
        }
    }
    
    public static void changeGroupPermission(DsUser user, String groupName,
            long permission) throws DashanException {
        Transaction tx = JDOHelper.getPersistenceManager(user).currentTransaction();
        tx.begin();
        try {
            user.getGroup(groupName).setPermissionBits(permission);
        } finally {
            if (tx.isActive()) {
                tx.commit();
            }
        }
        DsFriendGroup g = user.getGroup(groupName);
        
        if (g == null) {
            throw new DashanException("Group not found");
        }
        for (DsFriend f : user.getFriends()) {
            // Recalculate group permission;
            if (!f.isOverrideGroupPermission()) {
                f.setPermission(f.getGroupPermission());
            }
        }
    }
    
    public static void overrideGroupPermission(DsFriend friend, long permissionBits) {
        friend.setOverrideGroupPermission(true);
        friend.setPermission(permissionBits);
    }
    
    public static void useGroupPermission(DsFriend friend) throws DashanException {
        friend.setOverrideGroupPermission(false);
        friend.setPermission(friend.getGroupPermission());
    }
}
